#include "Acceptor.h"
#include "EventLoop.h"
#include "TcpConnection.h"
#include <iostream>

using std::cerr;
using std::cout;
using std::endl;

#include <unistd.h>
#include <sys/eventfd.h>
EventLoop::EventLoop(Acceptor &acceptor)
: _epfd(createEpollFd())
, _evtList(1024)
, _isLooping(false)
, _acceptor(acceptor)
, _evtfd(createEventFd())
{
    int listenfd = _acceptor.fd();
    addEpollReadFd(listenfd);
    addEpollReadFd(_evtfd);
}

EventLoop::~EventLoop()
{
    close(_epfd);
    close(_evtfd);
}

void EventLoop::loop()
{
    _isLooping = true;
    while(_isLooping)
    {
        waitEpollFd();
    }
}

void EventLoop::unloop()
{
    _isLooping = false;
}

int EventLoop::createEpollFd()
{
    int epfd = epoll_create1(0);
    if(epfd == -1)
    {
        perror("epoll_create1");
    }
    return epfd;
}

void EventLoop::addEpollReadFd(int fd)
{
    struct epoll_event evt;
    evt.data.fd = fd;
    evt.events = EPOLLIN;

    int ret = epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &evt);
    if(-1 == ret)
    {
        cerr << "addEpollReadFd" << endl;
        return;
    }
}
void EventLoop::delEpollReadFd(int fd)
{

    struct epoll_event evt;
    evt.data.fd = fd;
    evt.events = EPOLLIN;

    int ret = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, &evt);
    if(-1 == ret)
    {
        cerr << "delEpollReadFd" << endl;
        return;
    }
}

void EventLoop::waitEpollFd()
{
    int nready = 0;
    do{
        nready = epoll_wait(_epfd, _evtList.data(), _evtList.size(), 2000);
    }while(nready == -1 && errno == EINTR);//中断错误时持续监听

    if(nready == -1)
    {
        cerr << "waitEpollFd" << endl;
        return;
    }
    else if(nready == 0)
    {
        cout << ">>epoll_wait TIMEOUT." << endl;
    }
    else
    {
        if(nready == (int)_evtList.size())
        {
            _evtList.resize(2 * nready);
        }

        for(int i = 0; i < nready; i++)
        {
            int fd = _evtList[i].data.fd;
            int listenfd = _acceptor.fd();
            if(fd == listenfd)//新连接请求
            {
                if(_evtList[i].events & EPOLLIN)
                {
                    handleNewConnection();
                }
            }
            else if(fd == _evtfd)//监听到eventfd
            {
                if(_evtList[i].events & EPOLLIN)
                {
                    handleRead();//清0内核计数
                    doPengdingFunctors();//执行任务
                }
            }
            else//消息传递
            {
                if(_evtList[i].events & EPOLLIN)
                {
                    handleMessage(fd);
                }
            }

        }
    }
}

void EventLoop::handleNewConnection()
{
    int connfd = _acceptor.accept();
    if(-1 == connfd)
    {
        cerr << "handleNewConnection" << endl;
        return;
    }

    //监听新连接的fd
    addEpollReadFd(connfd);

    //更新map
    TcpConnectionPtr con(new TcpConnection(connfd, this));
    con->setNewConnectionCallback(_onNewConnection);
    con->setMessageCallback(_onMessage);
    con->setCloseCallback(_onClose);
    _conns[connfd] = con;

    con->handleNewConnectionCallback();
}

void EventLoop::handleMessage(int fd)
{
    auto it = _conns.find(fd);//查找连接
    if(it != _conns.end())//连接存在
    {
        bool isclose = it->second->isClose();
        if(!isclose)//未关闭
        {
            //消息传递
            it->second->handleMessageCallback();
        }
        else//已关闭
        {
            it->second->handleCloseCallback();
            //从红黑树上删除
            delEpollReadFd(fd);
            //更新map
            _conns.erase(it);
        }
    }
    else//连接不存在
    {
        cerr << "TcpConnection not exist." << endl;
        return;
    }
}

void EventLoop::setNewConnectionCallback(TcpConnectionCallback &&cb)
{
    _onNewConnection = std::move(cb);
}

void EventLoop::setMessageCallback(TcpConnectionCallback &&cb)
{
    _onMessage = std::move(cb);
}

void EventLoop::setCloseCallback(TcpConnectionCallback &&cb)
{
    _onClose = std::move(cb);
}

int EventLoop::createEventFd()
{
    int evtfd = eventfd(0,0);
    if(evtfd == -1)
    {
        cerr << "createEventFd" << endl;
    }
    return evtfd;
}

void EventLoop::wakeup()
{
    uint64_t one = 1;
    ssize_t ret = write(_evtfd, &one, sizeof(uint64_t));
    if(ret != sizeof(uint64_t))
    {
        cerr << "wakeup" << endl;
        return ;
    }
}

void EventLoop::handleRead()
{
    uint64_t one = 1;
    ssize_t ret = read(_evtfd, &one, sizeof(uint64_t));
    if(ret != sizeof(uint64_t))
    {
        cerr << "handleRead" << endl;
        return ;
    }
}

void EventLoop::doPengdingFunctors()
{
    //互斥取任务
    vector<Functor> tmp;
    {
        std::lock_guard<mutex> lg(_mutex);
        tmp.swap(_pengdings);
    }

    //遍历执行任务
    for(auto &cb : tmp)
    {
        cb();
    }
}

void EventLoop::runInLoop(Functor &&cb)
{
    //mutex添加任务
    {
        std::lock_guard<mutex> lg(_mutex);
        _pengdings.push_back(std::move(cb));
    }
    wakeup();//通知EventLoop执行任务
}
